package com.thor.palmmall.impl.pay;

import java.math.BigDecimal;
import java.nio.charset.Charset;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.thor.commons.exception.ThorServiceException;
import com.thor.commons.util.Assert;
import com.thor.commons.util.JsonUtil;
import com.thor.palmmall.api.pay.alipay.AliPayConfig;
import com.thor.palmmall.api.pay.alipay.MutiChannelAlipayService;
import com.thor.palmmall.api.statement.AStatementPayBill;
import com.thor.palmmall.api.statement.AStatementPayBillState;
import com.thor.palmmall.api.statement.StatementService;
import com.thor.palmmall.rest.event.StatementOrderSyncEvent;
import com.thor.palmmall.rest.user.AChannelContents;
import com.thor.palmmall.util.event.GlobalEventBus;
import com.thor.palmmall.util.pay.tool;

public class MutiChannelAlipayServiceImpl implements MutiChannelAlipayService {

  private Logger logger = LoggerFactory.getLogger(MutiChannelAlipayServiceImpl.class);
  private final String NOTIFY_FLAG_SUCCESS = "success";
  private final String NOTIFY_FLAG_FAILED = "failed";

  public static final String SUCCESS_REQUEST = "TRADE_SUCCESS";
  public static final String TRADE_CLOSED = "TRADE_CLOSED";

  @Override
  public String getTradePayRequestByChannel(Map<String, String> sParaTemp, AChannelContents channel)
      throws ThorServiceException {
    Assert.assertArgumentNotNull(sParaTemp, "sParaTemp");
    AlipayClient client = createAlipayClient(channel);

    AlipayTradeAppPayRequest alipayRequest = new AlipayTradeAppPayRequest();
    alipayRequest.setNotifyUrl(channel.getPAY_NOTIFY());
    // 待请求参数数组
    sParaTemp.put("seller_id", channel.getSELER_ID());
    alipayRequest.setBizContent(JsonUtil.objectToJson(sParaTemp));
    String form = "";
    try {
      form = client.sdkExecute(alipayRequest).getBody();
    } catch (AlipayApiException e) {
      throw new ThorServiceException("支付宝凭证生成失败");
    }
    logger.debug("支付宝支付表单构造:" + form);
    return form;
  }

  private AlipayClient createAlipayClient(AChannelContents channel) {
    AlipayClient client = new DefaultAlipayClient(channel.getGATEWAY(), channel.getAPP_ID(),
        channel.getPRIVATE_KEY(), "json", "utf-8", channel.getPUBLIC_KEY(), channel.getSIGN_TYPE());
    return client;
  }

  @Override
  public boolean callBack(String request) {
    List<NameValuePair> pairs = URLEncodedUtils.parse(request, Charset.forName("UTF-8"));
    Map<String, String> paranMap = new HashMap<String, String>();
    for (NameValuePair pair : pairs) {
      paranMap.put(pair.getName(), pair.getValue());
    }
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    logger.info("支付宝回调参数:" + paranMap.toString());
    AStatementPayBill bill = statementService.getByBillNumber(paranMap.get("out_trade_no"));
    if (bill.getNotifyFlag() != null && bill.getNotifyFlag().equals(this.NOTIFY_FLAG_SUCCESS)) {
      return true;
    }

    boolean isVerify = false;
    if (SUCCESS_REQUEST.equals(paranMap.get("trade_status"))
        || TRADE_CLOSED.equals(paranMap.get("trade_status"))) {
      try {
        isVerify = AlipaySignature.rsaCheckV1(paranMap, bill.getAlipayPublicKey(), "utf-8");
      } catch (AlipayApiException e) {
        logger.info("支付宝发生错误:" + e.getMessage());
        e.printStackTrace();
      }
    }
    // 调用SDK验证签名
    if (isVerify && AliPayConfig.SUCCESS_REQUEST.equals(paranMap.get("trade_status"))) {
      logger.info("支付成功改变充值单的状态:" + paranMap.toString());
      if (bill != null) {
        bill.setState(AStatementPayBillState.PAID);
        bill.setNotifyFlag(NOTIFY_FLAG_SUCCESS); // 回调使用单独的标志字段
        try {
          bill.setActionTime(dateFormat.parse(paranMap.get("gmt_create")));
        } catch (ParseException e) {
          e.printStackTrace();
        }
        bill.setBuyerLogonId(paranMap.get("buyer_logon_id"));
        bill.setBuyerPayAmount(new BigDecimal(paranMap.get("buyer_pay_amount")));
        bill.setInvoiceAmount(new BigDecimal(paranMap.get("invoice_amount")));
        bill.setReceiptAmount(new BigDecimal(paranMap.get("receipt_amount")));
        bill.setSellerEmail(paranMap.get("seller_email"));
        bill.setTransactioNo(paranMap.get("trade_no"));
        statementService.saveStatementPayBill(bill, tool.getOperateInfo());

        //开始同步订单任务
        StatementOrderSyncEvent event = new StatementOrderSyncEvent();
        event.setBill(bill);
        GlobalEventBus.post(event);
      }
      return true;
    } else {
      logger.info("验证签名失败:" + paranMap.toString());
      bill.setErrMsg(paranMap.get("trade_status"));
      bill.setNotifyFlag(NOTIFY_FLAG_FAILED);
      statementService.saveStatementPayBill(bill, tool.getOperateInfo());
      return isVerify;
    }
  }

  @Autowired
  private StatementService statementService;

}
